﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using ControleRepresentante.Common;

namespace ControleRepresentante.Logic.Models
{
    public class User : ModelBase
    {
        private readonly IList<Post> m_Posts;
        private readonly IList<Permissao> m_Permissoes;
        private readonly IList<IndexColumnsPreference> m_IndexColumnsPreferences;
        private readonly IList<UsuariosHolder> m_Filtros;

        public User()
        {
            Ativo = true;
            m_Permissoes = new List<Permissao>();
            m_Posts = new List<Post>();
            m_IndexColumnsPreferences = new List<IndexColumnsPreference>();
            m_Filtros = new List<UsuariosHolder>();
        }

        [Required(ErrorMessage = "*")]
        public virtual string Username { get; set; }
        public virtual Representante Representante { get; set; }
        public virtual bool Ativo { get; set; }
        [Required(ErrorMessage = "*")]
        [PasswordPropertyText]
        [DataType(DataType.Password)]
        public virtual string Password { get; protected set; }
        [ScaffoldColumn(false)]
        public virtual bool IsAdmin { get; set; }
        public virtual IEnumerable<Permissao> Permissoes { get { return m_Permissoes; } }
        public virtual IEnumerable<UsuariosHolder> Filtros { get { return m_Filtros; } }
        public virtual IEnumerable<Post> Posts { get { return m_Posts; } }
        public virtual string Email { get; set; }
        public virtual IEnumerable<IndexColumnsPreference> IndexColumnsPreferences { get { return m_IndexColumnsPreferences; } }

        public virtual void SetIndexColumnsPreferences(Area area, IEnumerable<Guid> builtInIndexColumns, IEnumerable<Attribute> attributeIndexColumns)
        {
            IndexColumnsPreference indexColumnsPreference = m_IndexColumnsPreferences.FirstOrDefault(x => x.Area == area);
            if (indexColumnsPreference == null)
            {
                indexColumnsPreference = new IndexColumnsPreference{User = this, Area = area};
                m_IndexColumnsPreferences.Add(indexColumnsPreference);
            }
            indexColumnsPreference.SetBuiltInIndexColumnPreferences(builtInIndexColumns);
            indexColumnsPreference.SetAttributeIndexColumnPreferences(attributeIndexColumns);
        }

        public virtual void SetPasswordFromRawText(string password)
        {
            if (password != Password)
            {
                Password = password.Encrypt();
            }
        }

        public virtual void ClearPassword()
        {
            Password = null;
        }

        public virtual void SetFiltros<T>(IEnumerable<T> usuariosHolders)
            where T : UsuariosHolder
        {
            IEnumerable<T> filtros = usuariosHolders.OfType<T>();
            UsuariosHolder[] toAdd = filtros.Except(Filtros).ToArray();
            UsuariosHolder[] toRemove = Filtros.Except(filtros).ToArray();
            foreach (UsuariosHolder usuariosHolder in toRemove)
            {
                usuariosHolder.RemoveUser(this);
                m_Filtros.Remove(usuariosHolder);
            }
            foreach (UsuariosHolder usuariosHolder in toAdd)
            {
                usuariosHolder.AddUser(this);
                m_Filtros.Add(usuariosHolder);
            }
        }

        public virtual bool HasPermission(Area area, Operacao operacao)
        {
            return HasPermission(area, operacao, Permissoes);}

        internal static bool HasPermission(Area area, Operacao operacao, IEnumerable<Permissao> permissoes)
        {
            return HasPermission(area, operacao, permissoes.ToDictionary(x => x.Area, x => x.Operacao));
        }

        internal static bool HasPermission(Area area, Operacao operacao, Dictionary<Area, Operacao> permissoes)
        {
            Operacao operacoes;
            return permissoes.TryGetValue(area, out operacoes) && (operacoes & operacao) == operacao;
        }

        public virtual void ClearPosts()
        {
            foreach (Post post in Posts.ToArray())
            {
                post.Pedido.RemovePost(post);
                post.User = null;
            }
        }

        public virtual void AddPermissao(Permissao permissao)
        {
            m_Permissoes.Add(permissao);
            permissao.User = this;
        }

        public virtual void ClearPermissoes()
        {
            foreach (Permissao permissao in Permissoes.ToArray())
            {
                m_Permissoes.Remove(permissao);
                permissao.User = null;
            }
        }
    }
}